import configparser
import os
from log_config import setup_logging
import logging

setup_logging()
logger = logging.getLogger(__name__)

class ConfigService:
    """
    配置服务类 - 采用单例模式实现
    负责加载、解析和提供配置文件中的所有配置项，确保配置访问的集中化、类型安全和错误处理
    """
    # 单例模式的实例引用和配置对象
    _instance = None
    _config = None
    
    @classmethod
    def get_instance(cls, config_path='config/config.ini'):
        """
        获取ConfigService的单例实例
        
        Args:
            config_path: 配置文件的路径，默认为'config/config.ini'
            
        Returns:
            ConfigService实例
        """
        if cls._instance is None:
            cls._instance = cls(config_path)
        return cls._instance
    
    def __init__(self, config_path='config/config.ini'):
        """
        私有构造函数，确保只在第一次调用时初始化配置
        
        Args:
            config_path: 配置文件的路径，默认为'config/config.ini'
        """
        if ConfigService._config is None:
            ConfigService._config = configparser.ConfigParser()
            # 检查配置文件是否存在
            if not os.path.exists(config_path):
                logger.error(f"配置文件不存在: {config_path}")
                raise FileNotFoundError(f"配置文件不存在: {config_path}")
            
            # 读取配置文件
            ConfigService._config.read(config_path, encoding='utf-8')
            logger.info(f"配置文件已加载: {config_path}")
            
            # 验证必要的配置节是否存在
            self._validate_config()
            
    def _validate_config(self):
        """
        验证必要的配置节和配置项是否存在
        """
        required_sections = ['backend', 'embedding', 'milvus', 'webserver']
        for section in required_sections:
            if not ConfigService._config.has_section(section):
                logger.warning(f"配置文件中缺少必要的配置节: {section}")
    
    def get(self, section: str, option: str, fallback=None) -> str:
        """
        获取配置项的值（字符串类型）
        
        Args:
            section: 配置节名称
            option: 配置项名称
            fallback: 默认值，当配置项不存在时返回
            
        Returns:
            配置项的值或默认值
            
        Raises:
            configparser.NoSectionError: 当section不存在且没有提供fallback时
            configparser.NoOptionError: 当option不存在且没有提供fallback时
        """
        try:
            if fallback is not None:
                return ConfigService._config.get(section, option, fallback=fallback)
            return ConfigService._config.get(section, option)
        except (configparser.NoSectionError, configparser.NoOptionError) as e:
            logger.warning(f"配置访问错误: {e}")
            if fallback is not None:
                return fallback
            raise
    
    def getint(self, section: str, option: str, fallback=None) -> int:
        """
        获取配置项的整数值
        
        Args:
            section: 配置节名称
            option: 配置项名称
            fallback: 默认值，当配置项不存在时返回
            
        Returns:
            配置项的整数值或默认值
            
        Raises:
            configparser.NoSectionError: 当section不存在且没有提供fallback时
            configparser.NoOptionError: 当option不存在且没有提供fallback时
            ValueError: 当配置值无法转换为整数时
        """
        try:
            if fallback is not None:
                return ConfigService._config.getint(section, option, fallback=fallback)
            return ConfigService._config.getint(section, option)
        except (configparser.NoSectionError, configparser.NoOptionError) as e:
            logger.warning(f"配置访问错误: {e}")
            if fallback is not None:
                return fallback
            raise
        except ValueError as e:
            logger.error(f"配置值转换为整数失败: {section}.{option}, 错误: {e}")
            if fallback is not None:
                return fallback
            raise
    
    def getboolean(self, section: str, option: str, fallback=None) -> bool:
        """
        获取配置项的布尔值
        
        Args:
            section: 配置节名称
            option: 配置项名称
            fallback: 默认值，当配置项不存在时返回
            
        Returns:
            配置项的布尔值或默认值
            
        Raises:
            configparser.NoSectionError: 当section不存在且没有提供fallback时
            configparser.NoOptionError: 当option不存在且没有提供fallback时
            ValueError: 当配置值无法转换为布尔值时
        """
        try:
            if fallback is not None:
                return ConfigService._config.getboolean(section, option, fallback=fallback)
            return ConfigService._config.getboolean(section, option)
        except (configparser.NoSectionError, configparser.NoOptionError) as e:
            logger.warning(f"配置访问错误: {e}")
            if fallback is not None:
                return fallback
            raise
        except ValueError as e:
            logger.error(f"配置值转换为布尔值失败: {section}.{option}, 错误: {e}")
            if fallback is not None:
                return fallback
            raise
    
    def getfloat(self, section: str, option: str, fallback=None) -> float:
        """
        获取配置项的浮点数值
        
        Args:
            section: 配置节名称
            option: 配置项名称
            fallback: 默认值，当配置项不存在时返回
            
        Returns:
            配置项的浮点数值或默认值
            
        Raises:
            configparser.NoSectionError: 当section不存在且没有提供fallback时
            configparser.NoOptionError: 当option不存在且没有提供fallback时
            ValueError: 当配置值无法转换为浮点数时
        """
        try:
            if fallback is not None:
                return ConfigService._config.getfloat(section, option, fallback=fallback)
            return ConfigService._config.getfloat(section, option)
        except (configparser.NoSectionError, configparser.NoOptionError) as e:
            logger.warning(f"配置访问错误: {e}")
            if fallback is not None:
                return fallback
            raise
        except ValueError as e:
            logger.error(f"配置值转换为浮点数失败: {section}.{option}, 错误: {e}")
            if fallback is not None:
                return fallback
            raise
    
    def get_embedding_config(self) -> dict:
        """
        获取嵌入模型相关配置
        
        Returns:
            包含模型名称和路径的字典
        """
        try:
            config = {
                'model_name': self.get('embedding', 'model_name', fallback=''),  # 嵌入模型名称
                'model_path': self.get('embedding', 'model_path', fallback='')   # 嵌入模型本地路径
            }
            logger.debug(f"获取嵌入模型配置: {config}")
            return config
        except Exception as e:
            logger.error(f"获取嵌入模型配置失败: {str(e)}")
            raise
    
    def get_rerank_config(self) -> dict:
        """
        获取重排序模型相关配置
        
        Returns:
            包含模型名称和路径的字典
        """
        try:
            config = {
                'model_name': self.get('rerank', 'model_name', fallback=''),  # 重排序模型名称
                'model_path': self.get('rerank', 'model_path', fallback='')   # 重排序模型本地路径
            }
            logger.debug(f"获取重排序模型配置: {config}")
            return config
        except Exception as e:
            logger.error(f"获取重排序模型配置失败: {str(e)}")
            raise
    
    def get_milvus_config(self) -> dict:
        """
        获取Milvus向量数据库相关配置
        
        Returns:
            包含主机地址和端口的字典
            
        Raises:
            configparser.NoSectionError: 当'milvus'配置节不存在时
            configparser.NoOptionError: 当必要的配置项不存在时
        """
        try:
            config = {
                'host': self.get('milvus', 'host', fallback='localhost'),  # Milvus服务器地址
                'port': self.get('milvus', 'port', fallback='19530')       # Milvus服务器端口
            }
            logger.debug(f"获取Milvus配置: {config}")
            return config
        except Exception as e:
            logger.error(f"获取Milvus配置失败: {str(e)}")
            raise
    
    def get_category_config(self) -> dict:
        """
        获取分类管理相关配置
        
        Returns:
            包含分类目录和文件的字典
            
        Raises:
            configparser.NoSectionError: 当'category'配置节不存在时
            configparser.NoOptionError: 当必要的配置项不存在时
        """
        try:
            config = {
                'category_dir': self.get('category', 'category_dir'),     # 分类文件存放目录
                'category_file': self.get('category', 'category_file')    # 分类文件名
            }
            # 确保分类目录存在
            category_dir = config['category_dir']
            if not os.path.exists(category_dir):
                logger.info(f"创建分类目录: {category_dir}")
                os.makedirs(category_dir)
            
            logger.debug(f"获取分类管理配置: {config}")
            return config
        except Exception as e:
            logger.error(f"获取分类管理配置失败: {str(e)}")
            raise
    
    def get_webserver_config(self) -> dict:
        """
        获取Web服务器相关配置
        
        Returns:
            包含端口号的字典
            
        Raises:
            configparser.NoSectionError: 当'webserver'配置节不存在时
            configparser.NoOptionError: 当必要的配置项不存在时
        """
        try:
            config = {
                'port': self.getint('webserver', 'port', fallback=8000)   # Web服务器监听端口
            }
            logger.debug(f"获取Web服务器配置: {config}")
            return config
        except Exception as e:
            logger.error(f"获取Web服务器配置失败: {str(e)}")
            raise
    
    def get_query_config(self) -> dict:
        """
        获取查询相关配置
        
        Returns:
            查询配置字典，包含top_k等参数
            
        Raises:
            configparser.NoSectionError: 当'query'配置节不存在时
            configparser.NoOptionError: 当必要的配置项不存在时
        """
        try:
            config = {
                'top_k': self.getint('query', 'top_k', fallback=5)  # 默认返回的结果数量
            }
            logger.debug(f"获取查询配置: {config}")
            return config
        except Exception as e:
            logger.error(f"获取查询配置失败: {str(e)}")
            raise
        
    
    def get_saved_images_config(self) -> dict:
        """
        获取保存图片相关配置
        
        Returns:
            包含图片保存目录的字典
            
        Raises:
            configparser.NoSectionError: 当'saved_images'配置节不存在时
            configparser.NoOptionError: 当必要的配置项不存在时
        """
        try:
            config = {
                'saved_images_dir': self.get('saved_images', 'saved_images_dir', fallback='saved_images')  # 图片保存目录
            }
            # 确保图片保存目录存在
            saved_dir = config['saved_images_dir']
            if not os.path.exists(saved_dir):
                logger.info(f"创建图片保存目录: {saved_dir}")
                os.makedirs(saved_dir)
            
            logger.debug(f"获取图片保存配置: {config}")
            return config
        except Exception as e:
            logger.error(f"获取图片保存配置失败: {str(e)}")
            raise
    
    
    def get_backend_config(self) -> dict:
        """
        获取后端服务相关配置
        
        Returns:
            包含后端名称的字典
            
        Raises:
            configparser.NoSectionError: 当'backend'配置节不存在时
            configparser.NoOptionError: 当必要的配置项不存在时
        """
        try:
            config = {
                'name': self.get('backend', 'name', fallback='HuggingFace')  # 后端服务名称
            }
            logger.debug(f"获取后端配置: {config}")
            return config
        except Exception as e:
            logger.error(f"获取后端配置失败: {str(e)}")
            raise